//
//  Problem468.swift
//  TestProject
//
//  Created by 武侠 on 2021/3/30.
//  Copyright © 2021 zhulong. All rights reserved.
//

import UIKit

/*
 468. 验证IP地址
 编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。

 如果是有效的 IPv4 地址，返回 "IPv4" ；
 如果是有效的 IPv6 地址，返回 "IPv6" ；
 如果不是上述类型的 IP 地址，返回 "Neither" 。
 IPv4 地址由十进制数和点来表示，每个地址包含 4 个十进制数，其范围为 0 - 255， 用(".")分割。比如，172.16.254.1；

 同时，IPv4 地址内的数不会以 0 开头。比如，地址 172.16.254.01 是不合法的。

 IPv6 地址由 8 组 16 进制的数字来表示，每组表示 16 比特。这些组数字通过 (":")分割。比如,  2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且，我们可以加入一些以 0 开头的数字，字母可以使用大写，也可以是小写。所以， 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即，忽略 0 开头，忽略大小写)。

 然而，我们不能因为某个组的值为 0，而使用一个空的组，以至于出现 (::) 的情况。 比如， 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。

 同时，在 IPv6 地址中，多余的 0 也是不被允许的。比如， 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。

 示例 1：
     输入：IP = "172.16.254.1"
     输出："IPv4"
    解释：有效的 IPv4 地址，返回 "IPv4"
 示例 2：
     输入：IP = "2001:0db8:85a3:0:0:8A2E:0370:7334"
     输出："IPv6"
     解释：有效的 IPv6 地址，返回 "IPv6"
 示例 3：
     输入：IP = "256.256.256.256"
     输出："Neither"
     解释：既不是 IPv4 地址，又不是 IPv6 地址
 示例 4：
     输入：IP = "2001:0db8:85a3:0:0:8A2E:0370:7334:"
     输出："Neither"
 示例 5：
     输入：IP = "1e1.4.5.6"
     输出："Neither"
 提示：
    IP 仅由英文字母，数字，字符 '.' 和 ':' 组成。
 */
@objcMembers class Problem468: NSObject {
    func solution() {
        print(validIPAddress("0.0.0.0"))
        print(validIPAddress("10.10.0."))
        print(validIPAddress(".0.0.91"))
        print(validIPAddress("0.0.0.0"))
        print(validIPAddress("172.16.254.1"))
        print(validIPAddress("2001:0db8:85a3:0:0:8A2E:0370:7334"))
        print(validIPAddress("256.256.256.256"))
        print(validIPAddress("2001:0db8:85a3:0:0:8A2E:0370:7334:"))
        print(validIPAddress("1e1.4.5.6"))
        print(validIPAddress(":0db8:85a3:0:0:8A2E:0370:7334:"))
        print(validIPAddress(":0db8:85a3:0:0:8A2E:0370:7334:1"))
        print(validIPAddress("3:0db8:85a3:0:0:8A2E:037M:7334:1"))
        print(validIPAddress("3:0db8:85a3:0:0::037M:7334:1"))
        print(validIPAddress("2001:0db8:85a3:0:0:8A2E:0370:73341"))
    }
    
    /*
     前提：
     IPV6:
     1: IPV6的IP[4] == ":"， 个数 = 7
     2: IPV6的字符只包含[0~9 A~F a~f]
     3: IPV6的长度 [15, 39]
     IPV4:
     1: IPV4只包含".",个数 = 4
     2: IPV4只包含数字,不能是0开头
     3: IPV6的长度 [7, 15]
     */
    func validIPAddress(_ IP: String) -> String {
        print(IP)
        if IP.count < 7 || IP.count > 39 {
            return "Neither"
        }
        
        let IPV4Charts:[Character] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."]
        let IPV6Charts:[Character] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "a", "b", "c", "d", "e", "f", ":"]
        
        var isIP = -1    // IPV4 = 0 IVP6 = 1
        let charts = Array(IP)
        // 首先判断是IPV4还是IP6
        for i in 0...4 {
            if i == 0 {
                if charts[i] == "." || charts[i] == ":" {
                    return "Neither"
                }
            } else if charts[i] == "." {
                isIP = 0
                break
            } else if charts[i] == ":" {
                isIP = 1
                break
            } else if IPV6Charts.contains(charts[i]) == false {
                return "Neither"
            }
        }

        // 判断IPV4
        if isIP == 0 {
            if IP.count > 15  {
                return "Neither"
            }
            var str:String = ""
            var dotNum = 0      // 点的个数
            for (i, c) in IP.enumerated() {
                if IPV4Charts.contains(c) == false {
                    return "Neither"
                } else if c != "." {
                    if c == "0" {
                        if str.count == 0 {
                            if i < IP.count-1, charts[i+1] != "." {
                                return "Neither"
                            } else if i > 0, charts[i-1] != "." {
                                return "Neither"
                            }
                        }
                    }
                    str.append(c)
                } else {
                    if str.count == 0 || str.count > 3 {
                        return "Neither"
                    } else if Int(str)! > 255 {
                        return "Neither"
                    }
                    str = ""
                    dotNum += 1
                }
            }
            return (dotNum == 3 && str.count > 0 && Int(str)! <= 255) ? "IPv4" : "Neither"
        } else {        // 判断IPV6
            if IP.count < 15  {
                return "Neither"
            }
            var str = 0         // 数字的个数
            var dotNum = 0      // :的个数
            for c in IP {
                if IPV6Charts.contains(c) == false {
                    return "Neither"
                } else if c != ":" {
                    str += 1
                } else {
                    if str == 0 || str > 4 {
                        return "Neither"
                    }
                    str = 0
                    dotNum += 1
                }
            }
            return (dotNum == 7 && str > 0 && str <= 4) ? "IPv6" : "Neither"
        }
    }
}
